---
interface Props {
  src: string
}

const { src } = Astro.props
---

<preview-copy data-src={src} class="hidden md:block">
  <button
    type="button"
    aria-label="Copy HTML"
    aria-pressed="false"
    class="inline-flex items-center gap-2 rounded-lg border border-stone-300 bg-white px-4 py-2 font-medium shadow-sm focus:ring-2 focus:ring-pink-500 focus:outline-0"
  >
    <span data-emoji aria-hidden="true">📋</span>
    <span data-text>Copy</span>
  </button>

  <span data-polite aria-live="polite" class="sr-only"> </span>
</preview-copy>

<script>
  type CopyVariant =
    | 'baseVariant'
    | 'isFirstVariant'
    | 'isHighlightedVariant'
    | 'isDetailedTextVariant'
    | 'isPrimaryVariant'

  class PreviewCopy extends HTMLElement {
    private isProcessing = false
    private contentSrc: string | null = null
    private copyVariant: CopyVariant = 'baseVariant'
    private timeoutId: ReturnType<typeof setTimeout> | null = null

    private clickHandler: (() => void) | null = null

    private resolveVariant(): CopyVariant {
      const storageKey = 'CopyVariant'
      const availableVariants: CopyVariant[] = [
        'baseVariant',
        'isFirstVariant',
        'isHighlightedVariant',
        'isDetailedTextVariant',
        'isPrimaryVariant',
      ]

      try {
        const storedVariant = sessionStorage.getItem(storageKey) as CopyVariant

        if (storedVariant && availableVariants.includes(storedVariant)) {
          return storedVariant
        }
      } catch {
        // We do nothing
      }

      const randomVariant = availableVariants[Math.floor(Math.random() * availableVariants.length)]

      try {
        sessionStorage.setItem(storageKey, randomVariant)
      } catch {
        // We do nothing
      }

      return randomVariant
    }

    connectedCallback() {
      this.contentSrc = this.dataset.src || null

      const assignedVariant = this.resolveVariant()

      this.copyVariant = assignedVariant

      if (!this.contentSrc) {
        return
      }

      const buttonEl = this.querySelector('button') as HTMLButtonElement | null
      const politeEl = this.querySelector('span[data-polite]') as HTMLSpanElement | null

      if (!buttonEl || !politeEl) {
        return
      }

      const variantClassMap: Record<CopyVariant, string[]> = {
        baseVariant: [],
        isFirstVariant: ['order-first'],
        isHighlightedVariant: [
          '[&>button]:relative',
          '[&>button]:before:-right-1',
          '[&>button]:before:-top-1',
          '[&>button]:before:absolute',
          '[&>button]:before:bg-pink-500',
          '[&>button]:before:rounded-full',
          '[&>button]:before:size-3',
          '[&>button]:after:-right-1',
          '[&>button]:after:-top-1',
          '[&>button]:after:[animation-duration:1.5s]',
          '[&>button]:after:absolute',
          '[&>button]:after:animate-ping',
          '[&>button]:after:bg-pink-300',
          '[&>button]:after:rounded-full',
          '[&>button]:after:size-3',
        ],
        isDetailedTextVariant: [],
        isPrimaryVariant: [
          '[&>button]:bg-pink-500/10',
          '[&>button]:border-pink-500',
          '[&>button]:shadow-pink-300',
        ],
      }

      const classesToAdd = variantClassMap[assignedVariant]

      if (classesToAdd.length) {
        this.classList.add(...classesToAdd)
      }

      const buttonEmoji = buttonEl.querySelector('span[data-emoji]') as HTMLSpanElement | null
      const buttonText = buttonEl.querySelector('span[data-text]') as HTMLSpanElement | null

      if (!buttonEmoji || !buttonText) {
        return
      }

      if (assignedVariant === 'isDetailedTextVariant') {
        buttonText.textContent = 'Copy HTML'
      }

      this.clickHandler = () => {
        if (this.isProcessing) {
          return
        }

        this.isProcessing = true

        if (this.timeoutId !== null) {
          clearTimeout(this.timeoutId)
        }

        document.dispatchEvent(
          new CustomEvent(`preview:copy:${this.contentSrc}`, {
            bubbles: true,
            detail: { variant: this.copyVariant },
          })
        )

        buttonEmoji.textContent = '✅'
        buttonText.textContent = 'Copied'
        politeEl.textContent = 'Copied to clipboard.'

        buttonEl.setAttribute('aria-pressed', 'true')

        this.timeoutId = globalThis.setTimeout(() => {
          if (this.isConnected) {
            buttonEmoji.textContent = '📋'
            buttonText.textContent =
              assignedVariant === 'isDetailedTextVariant' ? 'Copy HTML' : 'Copy'
            politeEl.textContent = ''

            buttonEl.setAttribute('aria-pressed', 'false')
          }

          this.isProcessing = false
        }, 1500)
      }

      buttonEl.addEventListener('click', this.clickHandler)
    }

    disconnectedCallback() {
      const buttonEl = this.querySelector('button') as HTMLButtonElement | null

      if (buttonEl && this.clickHandler) {
        buttonEl.removeEventListener('click', this.clickHandler)

        this.clickHandler = null
      }

      if (this.timeoutId !== null) {
        clearTimeout(this.timeoutId)

        this.timeoutId = null
      }
    }
  }

  customElements.define('preview-copy', PreviewCopy)
</script>
